home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 February: Tool Chest / Dev.CD Feb 99 TC.toast / What's New? / Development Kits / Mac OS USB v1.1f3 DDK / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-07  |  11.5 KB  |  347 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <DriverServices.h>
  16. #include <USB.h>
  17. #include <LowMem.h>
  18.  
  19. #include "MouseModule.h"
  20.  
  21. usbMousePBStruct myMousePB;
  22.  
  23. void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock)
  24. {
  25.     paramblock->usbReference = theInterfaceRef;
  26.     paramblock->pbVersion = kUSBCurrentPBVersion;
  27.     
  28.     paramblock->usb.cntl.WIndex = 0;             
  29.     paramblock->usb.cntl.WValue = 0;
  30.     
  31.     paramblock->usbBuffer = nil;        
  32.     paramblock->usbActCount = 0;
  33.     paramblock->usbReqCount = 0;
  34.     paramblock->usbFlags = 0;
  35.     paramblock->usbOther = 0;
  36.     
  37.     paramblock->usbStatus = noErr;
  38. }
  39.  
  40.  
  41.  
  42. Boolean immediateError(OSStatus err)
  43. {
  44.     return((err != kUSBPending) && (err != noErr) );
  45. }
  46.  
  47. void MouseInitiateTransaction(USBPB *pb)
  48. {
  49. register usbMousePBStruct *pMousePB;
  50. OSStatus myErr;
  51.  
  52.     pMousePB = (usbMousePBStruct *)(pb);
  53.     pMousePB->transDepth++;
  54.     if (pMousePB->transDepth < 0)
  55.     {
  56.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth < 0 (initiation)", pMousePB->pb.usbRefcon );
  57.     }
  58.     
  59.     if (pMousePB->transDepth > 1)
  60.     {
  61.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth > 1 (initiation)", pMousePB->pb.usbRefcon );
  62.     }
  63.     
  64.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  65.     {
  66.         case kConfigureInterface:
  67.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  68.             
  69.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  70.             pMousePB->pb.usbRefcon |= kCompletionPending;
  71.             
  72.             myErr = USBConfigureInterface( &pMousePB->pb );
  73.             if(immediateError(myErr))
  74.             {
  75.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kConfigureInterface - immediate error", myErr);
  76.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  77.             }
  78.             break;
  79.         
  80.         case kSetProtocol:
  81.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  82.             
  83.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  84.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  85.             pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  86.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  87.             
  88.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  89.             pMousePB->pb.usbRefcon |= kCompletionPending;
  90.         
  91.             myErr = USBDeviceRequest(&pMousePB->pb);
  92.             if (immediateError(myErr))
  93.             {
  94.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kSetProtocol - immediate error", myErr);
  95.             }
  96.             break;
  97.             
  98.         case kSetIdleRequest:
  99.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  100.             
  101.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  102.             
  103.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  104.             pMousePB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  105.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  106.             
  107.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  108.             pMousePB->pb.usbRefcon |= kCompletionPending;
  109.  
  110.             myErr = USBDeviceRequest(&pMousePB->pb);
  111.             if(immediateError(myErr))
  112.             {
  113.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kSetIdleRequest - immediate error", myErr);
  114.             }
  115.             break;
  116.  
  117.         case kFindPipe:
  118.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  119.             
  120.             pMousePB->pb.usbFlags = kUSBIn;
  121.             pMousePB->pb.usbClassType = kUSBInterrupt;
  122.             
  123.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  124.             pMousePB->pb.usbRefcon |= kCompletionPending;
  125.         
  126.             myErr = USBFindNextPipe( &pMousePB->pb );
  127.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  128.             {
  129.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: kFindPipe - immediate error", myErr);
  130.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  131.             }
  132.             break;
  133.         
  134.         case kClearFeature:
  135.             USBExpertStatus(pMousePB->interfaceRef, "\pUSBHIDMouseModule: Do a clear feature on the interrupt endpoint", pMousePB->pipeRef);
  136.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  137.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
  138.             
  139.             pMousePB->pb.usb.cntl.BRequest = kUSBRqClearFeature;
  140.             pMousePB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall;
  141.             
  142.             pMousePB->pb.usbFlags = kUSBAddressRequest;                /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */
  143.  
  144.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  145.             pMousePB->pb.usbRefcon |= kCompletionPending;
  146.  
  147.             myErr = USBDeviceRequest(pb);
  148.             if(immediateError(myErr))
  149.             {
  150.                 USBExpertFatalError(pMousePB->pb.usbReference, kUSBInternalErr, "\pUSBHIDMouseModule: kClearFeature - immediate error", myErr);
  151.             }
  152.             break;
  153.                 
  154.         case kReadInterruptPipe:
  155.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  156.  
  157.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  158.             pMousePB->pb.usbReqCount = pMousePB->maxPacketSize;
  159.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  160.             
  161.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  162.             pMousePB->pb.usbRefcon |= kCompletionPending;
  163.         
  164.             myErr = USBIntRead(&pMousePB->pb);
  165.             if(immediateError(myErr))
  166.             {
  167.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Read Interrupt Pipe (ImmediateError)", myErr);
  168.             }
  169.             break;
  170.             
  171.         default:
  172.             USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  173.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  174.             break;
  175.     }
  176.     
  177. // At this point the control is returned to the system.  If a USB transaction
  178. // has been initiated, then it will call the Complete procs
  179. // (below) to handle the results of the transaction.
  180. }
  181.  
  182.  
  183. void MouseCompletionProc(USBPB *pb)
  184. {
  185. register usbMousePBStruct *pMousePB;
  186. unsigned char    * errstring;
  187. USBPipeState     pipeState;
  188.  
  189.     pMousePB = (usbMousePBStruct *)(pb);
  190.     pMousePB->transDepth--;
  191.     if (pMousePB->transDepth < 0)
  192.     {
  193.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth < 0 (completion)", pMousePB->pb.usbRefcon );
  194.     }
  195.     
  196.     if (pMousePB->transDepth > 1)
  197.     {
  198.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule: transDepth > 1 (completion)", pMousePB->pb.usbRefcon );
  199.     }
  200.     
  201.     if(pMousePB->pb.usbStatus != noErr)                                                        // was there an error?
  202.     {
  203.         switch(pMousePB->pb.usbRefcon & 0x0fff)                                                // yes, so show where the error occurred
  204.         {
  205.             case kSetProtocol:                    errstring = "\pUSBHIDMouseModule: Error during kSetProtocol"; break;
  206.             case kSetIdleRequest:                  errstring = "\pUSBHIDMouseModule: Error during kSetIdleRequest"; break;
  207.             case kConfigureInterface:            errstring = "\pUSBHIDMouseModule: Error during kConfigureInterface"; break;
  208.             case kFindPipe:                      errstring = "\pUSBHIDMouseModule: Error during kFindPipe"; break;
  209.             case kClearFeature:                  errstring = "\pUSBHIDMouseModule: Error during kClearFeature"; break;
  210.             case kReadInterruptPipe:
  211.                 {
  212.                 errstring = "\pUSBHIDMouseModule: Error during ReadInterruptPipe";
  213.                 LMSetMouseButtonState(0x80);    // release any possibly held-down mouse button
  214.                 break;
  215.                 }
  216.             default:                              errstring = "\pUSBHIDMouseModule: Error occurred, but state is unknown"; break;
  217.         };
  218.         USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & 0x0fff));
  219.         
  220.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  221.         pMousePB->pb.usbRefcon |= kRetryTransaction;
  222.         pMousePB->retryCount--;
  223.         
  224.         if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon&pMousePB->pb.usbRefcon & 0x0fff) == kSetIdleRequest))
  225.         {
  226.             USBExpertStatus(pMousePB->interfaceRef, "\pUSBHIDMouseModule: Device doesn't accept SetIdle", pMousePB->interfaceRef);
  227.             pMousePB->pb.usbRefcon = kFindPipe;
  228.             pMousePB->pb.usbStatus = noErr;
  229.         }
  230.         else
  231.         {
  232.             if ((!pMousePB->retryCount)    || (pMousePB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  233.             {                                                                                // or received an abort?
  234.                 USBExpertStatus(pMousePB->interfaceRef, "\pUSBHIDMouseModule: Pipe abort or unable to recover from error", pMousePB->interfaceRef);
  235.                 pMousePB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  236.             }
  237.             else                                                                            // if it didn't abort and there's retries left, then...
  238.             {
  239.                 if (pMousePB->pipeRef)                                                        // check if the pipe is open.
  240.                 {
  241.                     USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                // yes, so what it's state?
  242.                     if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  243.                     {
  244.                         USBExpertStatus(pMousePB->interfaceRef, "\pUSBHIDMouseModule: Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  245.                         USBClearPipeStallByReference(pMousePB->pipeRef);
  246.                     }
  247.                 }
  248.             }
  249.         }
  250.     }
  251.     else
  252.     {
  253.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  254.         pMousePB->retryCount = kMouseRetryCount;
  255.     }
  256.  
  257.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  258.     {                                                
  259.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  260.         switch(pMousePB->pb.usbRefcon)
  261.         {
  262.             case kConfigureInterface:
  263.                 pMousePB->pb.usbRefcon = kSetProtocol;
  264.                 break;
  265.                 
  266.             case kSetProtocol:
  267.                 pMousePB->pb.usbRefcon = kSetIdleRequest;
  268.                 break;
  269.                 
  270.             case kSetIdleRequest:
  271.                 pMousePB->pb.usbRefcon = kFindPipe;
  272.                 break;
  273.                 
  274.             case kFindPipe:
  275.                 pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue;
  276.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  277.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  278.                 break;
  279.                 
  280.             case kReadInterruptPipe:
  281.                 NotifyRegisteredHIDUser(pMousePB->hidDeviceType, pMousePB->hidReport);
  282.                 pMousePB->pb.usbRefcon = kReadInterruptPipe;
  283.                 break;
  284.  
  285.             default:
  286.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, "\pUSBHIDMouseModule - Transaction completed with bad refcon value", pMousePB->pb.usbRefcon );
  287.                 pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  288.                 break;
  289.         }
  290.     }
  291.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver))
  292.         MouseInitiateTransaction(pb);
  293. }
  294.  
  295.  
  296. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theIntefaceRef)
  297. {
  298. #pragma unused (interfacenum)
  299.  
  300. static Boolean beenThereDoneThat = false;
  301.  
  302.     if(beenThereDoneThat)
  303.     {
  304.         USBExpertFatalError(theIntefaceRef, kUSBInternalErr, "\pUSBHIDMouseModule is not reentrant", 0);
  305.         return;
  306.     }
  307.     beenThereDoneThat = true;
  308.     
  309.     // DebugStr("\pIn Mouse Interface Entry routine");
  310.  
  311.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  312.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;            
  313.     
  314.     myMousePB.transDepth = 0;                            
  315.     myMousePB.retryCount = kMouseRetryCount;
  316.       
  317.     myMousePB.pSHIMInterruptRoutine = nil;
  318.     myMousePB.pSavedInterruptRoutine = nil;
  319.  
  320.     myMousePB.interfaceRef = theIntefaceRef;        
  321.     myMousePB.pipeRef = nil;        
  322.     
  323.     InitParamBlock(theIntefaceRef, &myMousePB.pb);
  324.     
  325.     myMousePB.pb.usbReference = theIntefaceRef;
  326.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  327.     myMousePB.pb.usbRefcon = kConfigureInterface;        
  328.     
  329.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  330.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  331.     {
  332.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  333.     }
  334.     else
  335.     {
  336.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  337.     }
  338.     
  339.     myMousePB.pCursorDeviceInfo = 0;                
  340.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  341.  
  342.     MouseInitiateTransaction(&myMousePB.pb);
  343. }
  344.  
  345.  
  346.  
  347.